home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / PIL / JpegImagePlugin.py < prev    next >
Text File  |  2006-12-03  |  14KB  |  431 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: JpegImagePlugin.py 2763 2006-06-22 21:43:28Z fredrik $
  4. #
  5. # JPEG (JFIF) file handling
  6. #
  7. # See "Digital Compression and Coding of Continous-Tone Still Images,
  8. # Part 1, Requirements and Guidelines" (CCITT T.81 / ISO 10918-1)
  9. #
  10. # History:
  11. # 1995-09-09 fl   Created
  12. # 1995-09-13 fl   Added full parser
  13. # 1996-03-25 fl   Added hack to use the IJG command line utilities
  14. # 1996-05-05 fl   Workaround Photoshop 2.5 CMYK polarity bug
  15. # 1996-05-28 fl   Added draft support, JFIF version (0.1)
  16. # 1996-12-30 fl   Added encoder options, added progression property (0.2)
  17. # 1997-08-27 fl   Save mode 1 images as BW (0.3)
  18. # 1998-07-12 fl   Added YCbCr to draft and save methods (0.4)
  19. # 1998-10-19 fl   Don't hang on files using 16-bit DQT's (0.4.1)
  20. # 2001-04-16 fl   Extract DPI settings from JFIF files (0.4.2)
  21. # 2002-07-01 fl   Skip pad bytes before markers; identify Exif files (0.4.3)
  22. # 2003-04-25 fl   Added experimental EXIF decoder (0.5)
  23. # 2003-06-06 fl   Added experimental EXIF GPSinfo decoder
  24. # 2003-09-13 fl   Extract COM markers
  25. #
  26. # Copyright (c) 1997-2003 by Secret Labs AB.
  27. # Copyright (c) 1995-1996 by Fredrik Lundh.
  28. #
  29. # See the README file for information on usage and redistribution.
  30. #
  31.  
  32. __version__ = "0.5"
  33.  
  34. import array, string
  35. import Image, ImageFile
  36.  
  37. def i16(c,o=0):
  38.     return ord(c[o+1]) + (ord(c[o])<<8)
  39.  
  40. def i32(c,o=0):
  41.     return ord(c[o+3]) + (ord(c[o+2])<<8) + (ord(c[o+1])<<16) + (ord(c[o])<<24)
  42.  
  43. #
  44. # Parser
  45.  
  46. def Skip(self, marker):
  47.     n = i16(self.fp.read(2))-2
  48.     ImageFile._safe_read(self.fp, n)
  49.  
  50. def APP(self, marker):
  51.     #
  52.     # Application marker.  Store these in the APP dictionary.
  53.     # Also look for well-known application markers.
  54.  
  55.     n = i16(self.fp.read(2))-2
  56.     s = ImageFile._safe_read(self.fp, n)
  57.  
  58.     app = "APP%d" % (marker&15)
  59.  
  60.     self.app[app] = s # compatibility
  61.     self.applist.append((app, s))
  62.  
  63.     if marker == 0xFFE0 and s[:4] == "JFIF":
  64.         # extract JFIF information
  65.         self.info["jfif"] = version = i16(s, 5) # version
  66.         self.info["jfif_version"] = divmod(version, 256)
  67.         # extract JFIF properties
  68.         try:
  69.             jfif_unit = ord(s[7])
  70.             jfif_density = i16(s, 8), i16(s, 10)
  71.         except:
  72.             pass
  73.         else:
  74.             if jfif_unit == 1:
  75.                 self.info["dpi"] = jfif_density
  76.             self.info["jfif_unit"] = jfif_unit
  77.             self.info["jfif_density"] = jfif_density
  78.     elif marker == 0xFFE1 and s[:5] == "Exif\0":
  79.         # extract Exif information (incomplete)
  80.         self.info["exif"] = s # FIXME: value will change
  81.     elif marker == 0xFFE2 and s[:5] == "FPXR\0":
  82.         # extract FlashPix information (incomplete)
  83.         self.info["flashpix"] = s # FIXME: value will change
  84.     elif marker == 0xFFEE and s[:5] == "Adobe":
  85.         self.info["adobe"] = i16(s, 5)
  86.         # extract Adobe custom properties
  87.         try:
  88.             adobe_transform = ord(s[1])
  89.         except:
  90.             pass
  91.         else:
  92.             self.info["adobe_transform"] = adobe_transform
  93.  
  94. def COM(self, marker):
  95.     #
  96.     # Comment marker.  Store these in the APP dictionary.
  97.  
  98.     n = i16(self.fp.read(2))-2
  99.     s = ImageFile._safe_read(self.fp, n)
  100.  
  101.     self.app["COM"] = s # compatibility
  102.     self.applist.append(("COM", s))
  103.  
  104. def SOF(self, marker):
  105.     #
  106.     # Start of frame marker.  Defines the size and mode of the
  107.     # image.  JPEG is colour blind, so we use some simple
  108.     # heuristics to map the number of layers to an appropriate
  109.     # mode.  Note that this could be made a bit brighter, by
  110.     # looking for JFIF and Adobe APP markers.
  111.  
  112.     n = i16(self.fp.read(2))-2
  113.     s = ImageFile._safe_read(self.fp, n)
  114.     self.size = i16(s[3:]), i16(s[1:])
  115.  
  116.     self.bits = ord(s[0])
  117.     if self.bits != 8:
  118.         raise SyntaxError("cannot handle %d-bit layers" % self.bits)
  119.  
  120.     self.layers = ord(s[5])
  121.     if self.layers == 1:
  122.         self.mode = "L"
  123.     elif self.layers == 3:
  124.         self.mode = "RGB"
  125.     elif self.layers == 4:
  126.         self.mode = "CMYK"
  127.     else:
  128.         raise SyntaxError("cannot handle %d-layer images" % self.layers)
  129.  
  130.     if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]:
  131.         self.info["progression"] = 1
  132.  
  133.     for i in range(6, len(s), 3):
  134.         t = s[i:i+3]
  135.         # 4-tuples: id, vsamp, hsamp, qtable
  136.         self.layer.append((t[0], ord(t[1])/16, ord(t[1])&15, ord(t[2])))
  137.  
  138. def DQT(self, marker):
  139.     #
  140.     # Define quantization table.  Support baseline 8-bit tables
  141.     # only.  Note that there might be more than one table in
  142.     # each marker.
  143.  
  144.     # FIXME: The quantization tables can be used to estimate the
  145.     # compression quality.
  146.  
  147.     n = i16(self.fp.read(2))-2
  148.     s = ImageFile._safe_read(self.fp, n)
  149.     while len(s):
  150.         if len(s) < 65:
  151.             raise SyntaxError("bad quantization table marker")
  152.         v = ord(s[0])
  153.         if v/16 == 0:
  154.             self.quantization[v&15] = array.array("b", s[1:65])
  155.             s = s[65:]
  156.         else:
  157.             return # FIXME: add code to read 16-bit tables!
  158.             # raise SyntaxError, "bad quantization table element size"
  159.  
  160.  
  161. #
  162. # JPEG marker table
  163.  
  164. MARKER = {
  165.     0xFFC0: ("SOF0", "Baseline DCT", SOF),
  166.     0xFFC1: ("SOF1", "Extended Sequential DCT", SOF),
  167.     0xFFC2: ("SOF2", "Progressive DCT", SOF),
  168.     0xFFC3: ("SOF3", "Spatial lossless", SOF),
  169.     0xFFC4: ("DHT", "Define Huffman table", Skip),
  170.     0xFFC5: ("SOF5", "Differential sequential DCT", SOF),
  171.     0xFFC6: ("SOF6", "Differential progressive DCT", SOF),
  172.     0xFFC7: ("SOF7", "Differential spatial", SOF),
  173.     0xFFC8: ("JPG", "Extension", None),
  174.     0xFFC9: ("SOF9", "Extended sequential DCT (AC)", SOF),
  175.     0xFFCA: ("SOF10", "Progressive DCT (AC)", SOF),
  176.     0xFFCB: ("SOF11", "Spatial lossless DCT (AC)", SOF),
  177.     0xFFCC: ("DAC", "Define arithmetic coding conditioning", Skip),
  178.     0xFFCD: ("SOF13", "Differential sequential DCT (AC)", SOF),
  179.     0xFFCE: ("SOF14", "Differential progressive DCT (AC)", SOF),
  180.     0xFFCF: ("SOF15", "Differential spatial (AC)", SOF),
  181.     0xFFD0: ("RST0", "Restart 0", None),
  182.     0xFFD1: ("RST1", "Restart 1", None),
  183.     0xFFD2: ("RST2", "Restart 2", None),
  184.     0xFFD3: ("RST3", "Restart 3", None),
  185.     0xFFD4: ("RST4", "Restart 4", None),
  186.     0xFFD5: ("RST5", "Restart 5", None),
  187.     0xFFD6: ("RST6", "Restart 6", None),
  188.     0xFFD7: ("RST7", "Restart 7", None),
  189.     0xFFD8: ("SOI", "Start of image", None),
  190.     0xFFD9: ("EOI", "End of image", None),
  191.     0xFFDA: ("SOS", "Start of scan", Skip),
  192.     0xFFDB: ("DQT", "Define quantization table", DQT),
  193.     0xFFDC: ("DNL", "Define number of lines", Skip),
  194.     0xFFDD: ("DRI", "Define restart interval", Skip),
  195.     0xFFDE: ("DHP", "Define hierarchical progression", SOF),
  196.     0xFFDF: ("EXP", "Expand reference component", Skip),
  197.     0xFFE0: ("APP0", "Application segment 0", APP),
  198.     0xFFE1: ("APP1", "Application segment 1", APP),
  199.     0xFFE2: ("APP2", "Application segment 2", APP),
  200.     0xFFE3: ("APP3", "Application segment 3", APP),
  201.     0xFFE4: ("APP4", "Application segment 4", APP),
  202.     0xFFE5: ("APP5", "Application segment 5", APP),
  203.     0xFFE6: ("APP6", "Application segment 6", APP),
  204.     0xFFE7: ("APP7", "Application segment 7", APP),
  205.     0xFFE8: ("APP8", "Application segment 8", APP),
  206.     0xFFE9: ("APP9", "Application segment 9", APP),
  207.     0xFFEA: ("APP10", "Application segment 10", APP),
  208.     0xFFEB: ("APP11", "Application segment 11", APP),
  209.     0xFFEC: ("APP12", "Application segment 12", APP),
  210.     0xFFED: ("APP13", "Application segment 13", APP),
  211.     0xFFEE: ("APP14", "Application segment 14", APP),
  212.     0xFFEF: ("APP15", "Application segment 15", APP),
  213.     0xFFF0: ("JPG0", "Extension 0", None),
  214.     0xFFF1: ("JPG1", "Extension 1", None),
  215.     0xFFF2: ("JPG2", "Extension 2", None),
  216.     0xFFF3: ("JPG3", "Extension 3", None),
  217.     0xFFF4: ("JPG4", "Extension 4", None),
  218.     0xFFF5: ("JPG5", "Extension 5", None),
  219.     0xFFF6: ("JPG6", "Extension 6", None),
  220.     0xFFF7: ("JPG7", "Extension 7", None),
  221.     0xFFF8: ("JPG8", "Extension 8", None),
  222.     0xFFF9: ("JPG9", "Extension 9", None),
  223.     0xFFFA: ("JPG10", "Extension 10", None),
  224.     0xFFFB: ("JPG11", "Extension 11", None),
  225.     0xFFFC: ("JPG12", "Extension 12", None),
  226.     0xFFFD: ("JPG13", "Extension 13", None),
  227.     0xFFFE: ("COM", "Comment", COM)
  228. }
  229.  
  230.  
  231. def _accept(prefix):
  232.     return prefix[0] == "\377"
  233.  
  234. ##
  235. # Image plugin for JPEG and JFIF images.
  236.  
  237. class JpegImageFile(ImageFile.ImageFile):
  238.  
  239.     format = "JPEG"
  240.     format_description = "JPEG (ISO 10918)"
  241.  
  242.     def _open(self):
  243.  
  244.         s = self.fp.read(1)
  245.  
  246.         if ord(s[0]) != 255:
  247.             raise SyntaxError("not a JPEG file")
  248.  
  249.         # Create attributes
  250.         self.bits = self.layers = 0
  251.  
  252.         # JPEG specifics (internal)
  253.         self.layer = []
  254.         self.huffman_dc = {}
  255.         self.huffman_ac = {}
  256.         self.quantization = {}
  257.         self.app = {} # compatibility
  258.         self.applist = []
  259.  
  260.         while 1:
  261.  
  262.             s = s + self.fp.read(1)
  263.  
  264.             i = i16(s)
  265.  
  266.             if MARKER.has_key(i):
  267.                 name, description, handler = MARKER[i]
  268.                 # print hex(i), name, description
  269.                 if handler is not None:
  270.                     handler(self, i)
  271.                 if i == 0xFFDA: # start of scan
  272.                     rawmode = self.mode
  273.                     if self.mode == "CMYK":
  274.                         rawmode = "CMYK;I"
  275.                     self.tile = [("jpeg", (0,0) + self.size, 0, (rawmode, ""))]
  276.                     # self.__offset = self.fp.tell()
  277.                     break
  278.                 s = self.fp.read(1)
  279.             elif i == 0 or i == 65535:
  280.                 # padded marker or junk; move on
  281.                 s = "\xff"
  282.             else:
  283.                 raise SyntaxError("no marker found")
  284.  
  285.     def draft(self, mode, size):
  286.  
  287.         if len(self.tile) != 1:
  288.             return
  289.  
  290.         d, e, o, a = self.tile[0]
  291.         scale = 0
  292.  
  293.         if a[0] == "RGB" and mode in ["L", "YCbCr"]:
  294.             self.mode = mode
  295.             a = mode, ""
  296.  
  297.         if size:
  298.             scale = max(self.size[0] / size[0], self.size[1] / size[1])
  299.             for s in [8, 4, 2, 1]:
  300.                 if scale >= s:
  301.                     break
  302.             e = e[0], e[1], (e[2]-e[0]+s-1)/s+e[0], (e[3]-e[1]+s-1)/s+e[1]
  303.             self.size = ((self.size[0]+s-1)/s, (self.size[1]+s-1)/s)
  304.             scale = s
  305.  
  306.         self.tile = [(d, e, o, a)]
  307.         self.decoderconfig = (scale, 1)
  308.  
  309.         return self
  310.  
  311.     def load_djpeg(self):
  312.  
  313.         # ALTERNATIVE: handle JPEGs via the IJG command line utilities
  314.  
  315.         import tempfile, os
  316.         file = tempfile.mktemp()
  317.         os.system("djpeg %s >%s" % (self.filename, file))
  318.  
  319.         try:
  320.             self.im = Image.core.open_ppm(file)
  321.         finally:
  322.             try: os.unlink(file)
  323.             except: pass
  324.  
  325.         self.mode = self.im.mode
  326.         self.size = self.im.size
  327.  
  328.         self.tile = []
  329.  
  330.     def _getexif(self):
  331.         # Extract EXIF information.  This method is highly experimental,
  332.         # and is likely to be replaced with something better in a future
  333.         # version.
  334.         import TiffImagePlugin, StringIO
  335.         def fixup(value):
  336.             if len(value) == 1:
  337.                 return value[0]
  338.             return value
  339.         # The EXIF record consists of a TIFF file embedded in a JPEG
  340.         # application marker (!).
  341.         try:
  342.             data = self.info["exif"]
  343.         except KeyError:
  344.             return None
  345.         file = StringIO.StringIO(data[6:])
  346.         head = file.read(8)
  347.         exif = {}
  348.         # process dictionary
  349.         info = TiffImagePlugin.ImageFileDirectory(head)
  350.         info.load(file)
  351.         for key, value in info.items():
  352.             exif[key] = fixup(value)
  353.         # get exif extension
  354.         file.seek(exif[0x8769])
  355.         info = TiffImagePlugin.ImageFileDirectory(head)
  356.         info.load(file)
  357.         for key, value in info.items():
  358.             exif[key] = fixup(value)
  359.         # get gpsinfo extension
  360.         try:
  361.             file.seek(exif[0x8825])
  362.         except KeyError:
  363.             pass
  364.         else:
  365.             info = TiffImagePlugin.ImageFileDirectory(head)
  366.             info.load(file)
  367.             exif[0x8825] = gps = {}
  368.             for key, value in info.items():
  369.                 gps[key] = fixup(value)
  370.         return exif
  371.  
  372. # --------------------------------------------------------------------
  373. # stuff to save JPEG files
  374.  
  375. RAWMODE = {
  376.     "1": "L",
  377.     "L": "L",
  378.     "RGB": "RGB",
  379.     "RGBA": "RGB",
  380.     "RGBX": "RGB",
  381.     "CMYK": "CMYK;I",
  382.     "YCbCr": "YCbCr",
  383. }
  384.  
  385. def _save(im, fp, filename):
  386.  
  387.     try:
  388.         rawmode = RAWMODE[im.mode]
  389.     except KeyError:
  390.         raise IOError("cannot write mode %s as JPEG" % im.mode)
  391.  
  392.     info = im.encoderinfo
  393.  
  394.     dpi = info.get("dpi", (0, 0))
  395.  
  396.     # get keyword arguments
  397.     im.encoderconfig = (
  398.         info.get("quality", 0),
  399.         # "progressive" is the official name, but older documentation
  400.         # says "progression"
  401.         # FIXME: issue a warning if the wrong form is used (post-1.1.5)
  402.         info.has_key("progressive") or info.has_key("progression"),
  403.         info.get("smooth", 0),
  404.         info.has_key("optimize"),
  405.         info.get("streamtype", 0),
  406.         dpi[0], dpi[1]
  407.         )
  408.  
  409.     ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)])
  410.  
  411. def _save_cjpeg(im, fp, filename):
  412.     # ALTERNATIVE: handle JPEGs via the IJG command line utilities.
  413.     import os
  414.     file = im._dump()
  415.     os.system("cjpeg %s >%s" % (file, filename))
  416.     try: os.unlink(file)
  417.     except: pass
  418.  
  419. # -------------------------------------------------------------------q-
  420. # Registry stuff
  421.  
  422. Image.register_open("JPEG", JpegImageFile, _accept)
  423. Image.register_save("JPEG", _save)
  424.  
  425. Image.register_extension("JPEG", ".jfif")
  426. Image.register_extension("JPEG", ".jpe")
  427. Image.register_extension("JPEG", ".jpg")
  428. Image.register_extension("JPEG", ".jpeg")
  429.  
  430. Image.register_mime("JPEG", "image/jpeg")
  431.